////////////////////////////////////////////////////////////////////////////////
//                                                                            //
//  Filename:    FieldOfGreenGuts.cpp                                         //
//  Developer:   Tommy Riddle                                                 //
//  Create date: 04/13/2007                                                   //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////
//                                                                            //
//  Description: This is the class implementation for the slot gut of the     //
//               RTG slot machine called Field Of Green.                      //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////
//        Copyright (c) 2007 - Realtime Gaming.  All rights reserved.         //
////////////////////////////////////////////////////////////////////////////////

#include "FieldOfGreenGuts.h"

////////////////////////////////////////////////////////////////////////////
/// FieldOfGreenGuts::m_aLineWinSpinResults
///
/// This array is used to quickly get the SpinResult for the number of
/// icons.  It is indexed by wheel icon and then count.  So to get the
/// SpinResult for 5 Aces, use the following code snippet:
///
///		SpinResult result = m_aLineWinSpinResults[ ICON_ACE ][ 5 ];
///
/// In this example result would be set to EVT_FIVE_ACE.
////////////////////////////////////////////////////////////////////////////
FieldOfGreenGuts::SpinResult FieldOfGreenGuts::m_aLineWinSpinResults[][6] = 
{
// Number of icons:			0			1				2					3						4						5
/* ICON_NINE */			{	EVT_LOSER,	EVT_LOSER,		EVT_LOSER,			EVT_THREE_NINE,			EVT_FOUR_NINE,			EVT_FIVE_NINE			},
/* ICON_TEN */			{	EVT_LOSER,	EVT_LOSER,		EVT_LOSER,			EVT_THREE_TEN,			EVT_FOUR_TEN,			EVT_FIVE_TEN			},
/* ICON_JACK */			{	EVT_LOSER,	EVT_LOSER,		EVT_LOSER,			EVT_THREE_JACK,			EVT_FOUR_JACK,			EVT_FIVE_JACK			},
/* ICON_QUEEN */		{	EVT_LOSER,	EVT_LOSER,		EVT_LOSER,			EVT_THREE_QUEEN,		EVT_FOUR_QUEEN,			EVT_FIVE_QUEEN			},
/* ICON_KING */			{	EVT_LOSER,	EVT_LOSER,		EVT_LOSER,			EVT_THREE_KING,			EVT_FOUR_KING,			EVT_FIVE_KING			},
/* ICON_ACE */			{	EVT_LOSER,	EVT_LOSER,		EVT_LOSER,			EVT_THREE_ACE,			EVT_FOUR_ACE,			EVT_FIVE_ACE			},
/* ICON_BEER */			{	EVT_LOSER,	EVT_LOSER,		EVT_LOSER,			EVT_THREE_BEER,			EVT_FOUR_BEER,			EVT_FIVE_BEER			},
/* ICON_FOAM_FINGER */	{	EVT_LOSER,	EVT_LOSER,		EVT_LOSER,			EVT_THREE_FOAM_FINGER,	EVT_FOUR_FOAM_FINGER,	EVT_FIVE_FOAM_FINGER	},
/* ICON_CHEERLEADER */	{	EVT_LOSER,	EVT_LOSER,		EVT_LOSER,			EVT_THREE_CHEERLEADER,	EVT_FOUR_CHEERLEADER,	EVT_FIVE_CHEERLEADER	},
/* ICON_WHISTLE */		{	EVT_LOSER,	EVT_LOSER,		EVT_LOSER,			EVT_THREE_WHISTLE,		EVT_FOUR_WHISTLE,		EVT_FIVE_WHISTLE		},
/* ICON_HELMET */		{	EVT_LOSER,	EVT_LOSER,		EVT_TWO_HELMET,		EVT_THREE_HELMET,		EVT_FOUR_HELMET,		EVT_FIVE_HELMET			},
/* ICON_PLAYER */		{	EVT_LOSER,	EVT_LOSER,		EVT_TWO_PLAYER,		EVT_THREE_PLAYER,		EVT_FOUR_PLAYER,		EVT_FIVE_PLAYER			},
/* ICON_FOOTBALL */		{	EVT_LOSER,	EVT_LOSER,		EVT_LOSER,			EVT_LOSER,				EVT_LOSER,				EVT_LOSER				},
/* ICON_TROPHY */		{	EVT_LOSER,	EVT_LOSER,		EVT_LOSER,			EVT_LOSER,				EVT_LOSER,				EVT_LOSER				}
};

////////////////////////////////////////////////////////////////////////////
/// @fn 	 FieldOfGreenGuts::FieldOfGreenGuts()   
///
/// This is the default constructor for the class.
////////////////////////////////////////////////////////////////////////////
FieldOfGreenGuts::FieldOfGreenGuts()
{
	// If this doesn't compile it means that someone probably added
	// another icon type but did not update the
	// m_aLineWinSpinResults array. 
	C_ASSERT( countof( m_aLineWinSpinResults ) == NUM_VALID_ICONS );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 FieldOfGreenGuts::~FieldOfGreenGuts()
///
/// Destructor for FieldOfGreenGuts. 
////////////////////////////////////////////////////////////////////////////
FieldOfGreenGuts::~FieldOfGreenGuts()
{
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 FieldOfGreenGuts::SpinResult FieldOfGreenGuts::getLineWinResultWithPossibleSubstitution( uint8* stops, uint8 testIcon, bool& bSubstitution ) const
///
/// @param   stops			The array of stop positions for the line.
/// @param   bSubstitution	An output parameter that is set if a subsitution is used.
///
/// @return	 SpinResult		A payout from the SpinResult enumeration.
///
/// This helper method is used to calculate the line win payout with a possible substitution.
////////////////////////////////////////////////////////////////////////////
FieldOfGreenGuts::SpinResult FieldOfGreenGuts::getLineWinResultWithPossibleSubstitution(
	uint8* stops, uint8 line, EvalType et, bool& bSubstitution )
{
	// Initialize the out parameter
	bSubstitution = false;

	// Keep up with the direction we are going.
	int nDirection;

	// We need a place to keep up with the starting reel since we can go
	// in either direction.
	int nStartReel;

	// If we are going from left to right...
	if ( et == etLeftToRight )
	{
		// then start at reel 0.
		nStartReel = 0;

		// We will need to increment the reel as we iterate through the loop.
		nDirection = 1;
	}
	else
	{
		// Otherwise we must be going from right to left.
		ASSERT( et == etRightToLeft );

		// Start on the last reel.
		nStartReel = getReelCount() - 1;

		// We will need to decrement the reel as we iterate through the loop.
		nDirection = -1;
	}

	// The icon we are testing for.
	uint8 testIcon = getIcon( getGameModeId(), nStartReel, stops[ nStartReel ] )->iconid;

	// Loop through the remaining reels until the streak is over
	for ( int i = 1; i < getReelCount(); i++ )
    {
		// Figure out what our current reel is for this iteration.
		int nCurrentReel = nStartReel + ( i * nDirection );

		// See what this icon is.
		uint8 currentIcon = getIcon( getGameModeId(), nCurrentReel, stops[ nCurrentReel ] )->iconid;

		// If the current icon is a Trophy...
		if ( currentIcon == ICON_TROPHY )
		{
			// then use it as a substitution symbol and continue on.
			bSubstitution = true;
			continue;
		}
		// Otherwise if the test icon is a Trophy...
		else if ( testIcon == ICON_TROPHY )
		{
			// then we still have a substitution.  In this case the line
			// started out with a TROPHY.
			bSubstitution = true;

			// We have now found our first icon that is not a Trophy.  All
			// of the rest of the icons will have to match this one now for the
			// streak to continue, so change our test icon.
			testIcon = currentIcon;
			continue;
		}

		// If the current icon is not the test icon...
        if ( currentIcon != testIcon )
        {
			// then the streak is over so break out of the loop
			break;
        }
    }

	// Use the array to look up the spin result for i testIcons.
	return lookupLineWinSpinResult( testIcon, i );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 bool FieldOfGreenGuts::::doesRightToLeftLineWinPayMore( SpinResult srLeftToRight, bool bLeftToRightSubstitution, SpinResult srRightToLeft, bool bRightToLeftSubstitution ) const;
///
/// @param   srLeftToRight	The spin result to calculate the left to right payout for.
/// @param   srRightToLeft	The spin result to calculate the right to left payout for.
///
/// @return	 bool			True if the right to left win is larger.
///
/// This helper method is used to see which payout is larger.
////////////////////////////////////////////////////////////////////////////
bool FieldOfGreenGuts::doesRightToLeftLineWinPayMore( SpinResult srLeftToRight, bool bLeftToRightSubstitution,
	SpinResult srRightToLeft, bool bRightToLeftSubstitution ) const
{
	// Lookup the payout for the left to right line win.
	long nLeftToRightLineWinPayout = getPayout( srLeftToRight )->payoutAmount;

	// If we had a left to right substitution...
	if ( bLeftToRightSubstitution )
	{
		// then factor in the multiplier.
		nLeftToRightLineWinPayout *= MULTIPLIER_SUBSTITUTION;
	}

	// Lookup the payout for the right to left line win.
	long nRightToLeftLineWinPayout = getPayout( srRightToLeft )->payoutAmount;

	// If we had a right to left substitution...
	if ( bRightToLeftSubstitution )
	{
		// then factor in the multiplier.
		nRightToLeftLineWinPayout *= MULTIPLIER_SUBSTITUTION;
	}

	// If the payout is the same for both directions...
	if ( nRightToLeftLineWinPayout == nLeftToRightLineWinPayout )
	{
		// then return true if right to left had a substitution but left to right didn't.
		return ( !bLeftToRightSubstitution && bRightToLeftSubstitution );
	}

	// Return true if the right to left payout is bigger.
    return ( nRightToLeftLineWinPayout > nLeftToRightLineWinPayout );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 FieldOfGreenGuts::classifyStops()   
///
/// @param   stops      The array of stop positions for the line.
/// @param   bet        The value of the line bet.
/// @param   line       The index of the line.
///
/// @return	 uint8      A payout from the SpinResult enumeration as a uint8.    
///
/// This helper method is used to calculate the payout on a line.
////////////////////////////////////////////////////////////////////////////
void FieldOfGreenGuts::classifyStops( SpinLine* spinline, uint8* stops, uint8 bet, uint8 line,
	uint8& rtnresult, uint8& multiplier )
{
	// Keep up with whether or not we have a substitution on the rtnresult.
	bool bSubstitution = false;

	// See what the payout is going left to right.
	// Declare a local variable to track whether or not we found a substitution.
	bool bLeftToRightSubstitution = false;

	// See what the spin result is if we used any Trophy icons as substitution symbols.
	SpinResult srLeftToRightResult = getLineWinResultWithPossibleSubstitution( stops, line,
		etLeftToRight, bLeftToRightSubstitution );

	// Now see what the payout is going right to left.
	// Declare a local variable to track whether or not we found a substitution.
	bool bRightToLeftSubstitution = false;

	// See what the spin result is if we used any Trophy icons as substitution symbols.
	SpinResult srRightToLeftResult = getLineWinResultWithPossibleSubstitution( stops, line,
		etRightToLeft, bRightToLeftSubstitution );

	// Use the larger payout between the two.
    if ( doesRightToLeftLineWinPayMore( srLeftToRightResult, bLeftToRightSubstitution,
		srRightToLeftResult, bRightToLeftSubstitution ) )
	{
		// The right to left win pays more.
		rtnresult = srRightToLeftResult;

		// Use the right to left substitution flag.
		bSubstitution = bRightToLeftSubstitution;

		// Set the right to left line win flag to make things easier for the client.
		setRightToLeftLineWin( line );
	}
	else
	{
		// Otherwise the left to right win pays more.
		rtnresult = srLeftToRightResult;

		// Use the left to right substitution flag.
		bSubstitution = bLeftToRightSubstitution;
	}

	// If we did actually have a substitution and a winning spin...
	if ( bSubstitution && rtnresult != EVT_LOSER )
	{
		// then add a note and change the multiplier.
		spinline->addNote( NOTE_SUBSTITUTION );
		multiplier = MULTIPLIER_SUBSTITUTION;
	}
}

////////////////////////////////////////////////////////////////////////////
/// @fn		FieldOfGreenGuts::tryForJackpot()
///
///	This function tries to win the jackpot and adds the scatter if we hit
/// the jackpot.
////////////////////////////////////////////////////////////////////////////
void FieldOfGreenGuts::tryForJackpot( SlotSpin* spin )
{
	// If we are in the first paid spin (NOT a bonus spin)...
	if ( getGameModeId() == MODE_NORMAL ) 
	{
		// then try for the Random Progressive Jackpot
		// If we hit the jackpot...
		if ( getRandomProgressiveJackpotResult( getNumLinesBet() ) || 
             m_bForceRandomJackpot == true )
		{
			// then add a jackpot scatter to the spin.
			spin->addScatter( 0,
				getPayout( EVT_RANDOM_PROGRESSIVE_WINNER )->payoutAmount, 1,
				true, EVT_RANDOM_PROGRESSIVE_WINNER, 0 );
		}
    }
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 FieldOfGreenGuts::evaluateFeatureTriggerSteps()   
///
/// @param   spin						The current spin object.
///
/// This helper method is used to evaluate the spin for feature trigger
/// steps.
////////////////////////////////////////////////////////////////////////////
void FieldOfGreenGuts::evaluateFeatureTriggerSteps(  SlotSpin* spin )
{
	// Keep up with the current trigger step.
	int32 nCurrentStep = 0;

	// Keep up with how many reels are left.
	int32 nReelsRemaining = getReelCount();

	// Loop through each reel.
  	for( int reel = 0; reel < getReelCount(); reel++ )
	{
		// Keep up with whether or not we found a scatter icon on this reel.
		bool bFoundIconOnReel = false;

		// If it is impossible to still trigger the feature...
		if ( nCurrentStep + nReelsRemaining < 3 )
		{
			// then just stop now.
			break;
		}

		// Decrement the number of reels remaining.
		nReelsRemaining--;

		// If we are at step 2 or higher...
		if ( nCurrentStep >= 2 )
		{
			// and we are on reel 2 or reel 4...
			if ( reel == 2 || reel == 4 )
			{
				// and the feature is not already triggered...
				if ( !getFeatureTriggered() )
				{
					// then this reel is an anticipation reel.
					setReelAnticipation( reel, true );
				}
			}
		}

		// Loop through each row in the wheel house.
		for( int row = 0; row < 3; row++ )
		{
			// Get the current stop.
			uint8 stop = relativeWheelPosition( getGameModeId(), reel,
				spin->getStops()[ reel ], row );

			// Get the icon for the current stop.
			uint8 currentIcon = getIcon( getGameModeId(), reel, stop )->iconid;
			
			// If the icon is the one we are looking for...
			if ( currentIcon == ICON_FOOTBALL )
			{
				// then set the flag so that we know we found a scatter icon on this reel.
				bFoundIconOnReel = true;

				// No need to keep looking on this reel.
				break;
			}
		}

		// If we found an icon on the reel...
		if ( bFoundIconOnReel )
		{
			// then we are at the next step.
			nCurrentStep++;

			// If we are at least at step 3...
			if ( nCurrentStep >= 3 )
			{
				// and we are on reel 2 or reel 4...
				if ( reel == 2 || reel == 4 )
				{
					// then we triggered the feature.
					setFeatureTriggered( true );
				}
			}
		}
		// Otherwise...
		else
		{
			// reset back to 0.
			nCurrentStep = 0;
		}

		// Store the current step in the sub-game data.
		setReelFeatureTriggerStep( reel, nCurrentStep );
	}
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 FieldOfGreenGuts::getScatterResult()   
///
/// @param   spin						The current spin object.
/// @param   nNumWhiteLightIcons		The number of white light icons that we find.
/// @param   nWhiteLightPositions		The bit mask for the white light positions that we find.
///
/// @return	 SpinResult			A payout from the SpinResult enumeration.
///
/// This helper method is used to evaluate the spin for scatters.
////////////////////////////////////////////////////////////////////////////
FieldOfGreenGuts::SpinResult FieldOfGreenGuts::getScatterResult(  SlotSpin* spin, EvalType et, int32& nNumIcons, int32& nPositions ) const
{
	// Initialize the counter and scatter positions.
	nNumIcons = 0;
	nPositions = 0;

	// Keep up with the direction we are going.
	int nDirection;

	// We need a place to keep up with the starting reel since we can go
	// in either direction.
	int nStartReel;

	// If we are going from left to right...
	if ( et == etLeftToRight )
	{
		// then start at reel 0.
		nStartReel = 0;

		// We will need to increment the reel as we iterate through the loop.
		nDirection = 1;
	}
	else
	{
		// Otherwise we must be going from right to left.
		ASSERT( et == etRightToLeft );

		// Start on the last reel.
		nStartReel = getReelCount() - 1;

		// We will need to decrement the reel as we iterate through the loop.
		nDirection = -1;
	}

	// Loop through each reel.
  	for( int i = 0; i < getReelCount(); i++ )
	{
		// Figure out what our current reel is for this iteration.
		int reel = nStartReel + ( i * nDirection );

		// The position bit for the current icon in case it needs to be stored in a mask.
		uint8 position = reel;

		// Keep up with whether or not we found a scatter icon on this reel.
		bool bFoundIconOnReel = false;

		// Loop through each row in the wheel house.
		for( int row = 0; row < 3; row++ )
		{
			// Get the current stop.
			uint8 stop = relativeWheelPosition( getGameModeId(), reel,
				spin->getStops()[ reel ], row );

			// Get the icon for the current stop.
			uint8 currentIcon = getIcon( getGameModeId(), reel, stop )->iconid;
			
			// If the icon is a Football...
			if ( currentIcon == ICON_FOOTBALL )
			{
				// then increase the count
				nNumIcons++;

				// Set the bit in the position mask for this stop.
				nPositions |= 1 << position;

				// Set the flag so that we know we found a scatter icon on this reel.
				bFoundIconOnReel = true;
			}

			// Move to the next bit in the position mask.
            position += 5;
		}

		// If we didn't find a icon on the reel...
		if (! bFoundIconOnReel )
		{
			// then we are done.
			break;
		}
	}

	// This game only pays out for 2 scatter icons.  Any more than that will trigger the feature but
	// does not pay any money for the scatter.
	if ( nNumIcons == 2 )
	{
		return EVT_TWO_FOOTBALL;
	}

	// No scatter win.
	return EVT_LOSER;
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 FieldOfGreenGuts::addScatter()
///
/// This function determines if the current spin wins a scatter payment and
/// adds the scatter.
////////////////////////////////////////////////////////////////////////////
void FieldOfGreenGuts::addScatter( SlotSpin* spin, SpinResult srResult, int32 nPositions )
{
	// If we got the scatter win...
	if ( srResult != EVT_LOSER )
	{
		// then initialize our multiplier for scatters.
		int32 multiplier = 1;

		// If we are in free spin mode...
		if ( getGameModeId() == MODE_FREE_SPIN )
		{
			// then use the free spin scatter multiplier.
			multiplier = MULTIPLIER_FREE_SPIN;
		}

		// Get the base payout for the scatter.
		int32 nPayout = getPayout( srResult )->payoutAmount;
		
		// Scatters payout based on the total bet, so factor in the number of bet lines.
		nPayout *= getNumLinesBet();

		// Add the payout (with multiplier) to the total win for this spin.
		increaseTotalWin( nPayout * multiplier );
    
		// Add a scatter to the spin.
		SlotScatter* pScatter = spin->addScatter( nPositions,
			nPayout * getBetPerLine(), multiplier, false, srResult, 0 );

		// If the free spin multiplier was used...
		if ( multiplier == MULTIPLIER_FREE_SPIN )
		{
			// then add the free spin note.
			pScatter->addNote( NOTE_FREE_SPIN );
		}
	}
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 FieldOfGreenGuts::addFeatureTriggerScatter()
///
/// This function determines if the current spin triggered the bonus game
/// and adds the appropriate scatter.
////////////////////////////////////////////////////////////////////////////
void FieldOfGreenGuts::addFeatureTriggerScatter( SlotSpin* spin, int32 nNumIcons, int32 nPositions )
{
	// If there were at least 3 scatter icons...
	if ( nNumIcons >= 3 )
	{
		// then set the number of kicks.
		setNumKicks( nNumIcons );

		// Add the field goal feature.
		spin->addScatter( nPositions, 0, 0, false, EVT_FIELD_GOAL_FEATURE, 0 );

		// If we have not reached the maximum payout already...
		if ( getTotalWin() < getFeatureGameCap() )
		{
			// then the game can't complete until the bonus game is done.
			setGameCanComplete( false );
			setBonusGameState( BONUS_GAME_ACTIVE );
		}
	}
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 FieldOfGreenGuts::addBonus()
///
/// This helper method is used to add the field goal bonus. 
////////////////////////////////////////////////////////////////////////////
void FieldOfGreenGuts::addBonus( uint8 nResult )
{
	// Keep up with the multiplier prize, if any.
	int32 nPrize = 0;

	// Keep up with how many free spins they get, if any.
	int32 nFreeSpins = 0;

	// See what they won.
	switch ( nResult )
	{
		case KR_2X:
		{
			nPrize = 2;
		}
		break;

		case KR_5X:
		{
			nPrize = 5;
		}
		break;

		case KR_10X:
		{
			nPrize = 10;
		}
		break;

		case KR_15X:
		{
			nPrize = 15;
		}
		break;

		case KR_25X:
		{
			nPrize = 25;
		}
		break;

		case KR_50X:
		{
			nPrize = 50;
		}
		break;

		case KR_100X:
		{
			nPrize = 100;
		}
		break;

		case KR_5_GAMES:
		{
			nFreeSpins = 5;
		}
		break;

		case KR_10_GAMES:
		{
			nFreeSpins = 10;
		}
		break;

		case KR_25_GAMES:
		{
			nFreeSpins = 25;
		}
		break;

		default:
		{
			ASSERT( nResult == KR_MISS );
		}
		break;
	}

	// Calculate the bonus prize, if any.
	int32 nBasePayoutAmount = getBetPerLine() * getNumLinesBet() * nPrize;

	// Add the free spins, if any
	incrementFreeSpins( nFreeSpins );

	// If they won something...
	if ( nPrize || nFreeSpins )
	{
		// Add the bonus game result.
		addBonusGame( BONUS_GAME_FIELD_GOAL_FEATURE, getCurrentKick(), nBasePayoutAmount, 1, nBasePayoutAmount, nFreeSpins );
	}
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 FieldOfGreenGuts::classifyScatters( SlotSpin* spin )
///
/// @param   spin       Pointer to the spin with stop data.
///
/// This is an override of the framework method.  
/// It determines if the current spin merits free spins or scatter payments.
////////////////////////////////////////////////////////////////////////////
void FieldOfGreenGuts::classifyScatters( SlotSpin* spin )
{	
	// Try for the Random Progressive Jackpot
	tryForJackpot( spin );

	// Look for feature trigger steps.
	evaluateFeatureTriggerSteps( spin );

	// See what the payout is going left to right.
	// Declare a local variable to track the scatter positions.
	int32 nLeftToRightScatterPositions = 0;

	// Declare a local variable to track the number of icons.
	int32 nLeftToRightNumIcons = 0;

	// See what the spin result is going left to right.
	SpinResult srLeftToRightResult = getScatterResult( spin,
		etLeftToRight, nLeftToRightNumIcons, nLeftToRightScatterPositions );

	// Now see what the payout is going right to left.
	// Declare a local variable to track the scatter positions.
	int32 nRightToLeftScatterPositions = 0;

	// Declare a local variable to track the number of icons.
	int32 nRightToLeftNumIcons = 0;

	// See what the spin result is going right to left.
	SpinResult srRightToLeftResult = getScatterResult( spin,
		etRightToLeft, nRightToLeftNumIcons, nRightToLeftScatterPositions );

	// Scatters payout left to right and right to left.
	// First add the left to right scatter.
	addScatter( spin, srLeftToRightResult, nLeftToRightScatterPositions );

	// Now add the left to right feature trigger scatter.
	addFeatureTriggerScatter( spin, nLeftToRightNumIcons, nLeftToRightScatterPositions );

	// If the left to right scatter was not for 5 icons...
	if ( nLeftToRightNumIcons != 5 )
	{
		// then also add the right to left scatter.
		addScatter( spin, srRightToLeftResult, nRightToLeftScatterPositions );
		
		// Now add the right to left feature trigger scatter.
		addFeatureTriggerScatter( spin, nRightToLeftNumIcons, nRightToLeftScatterPositions );
	}
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 FieldOfGreenGuts::isValidGuts()   
///
/// @return	 bool8      True if gut is valid.    
///
/// This helper method is used to see if the current gut ID is valid.
////////////////////////////////////////////////////////////////////////////
bool8 FieldOfGreenGuts::isValidGuts()
{
	// Make sure that the m_aLineWinSpinResults array has an entry for each reel,
	// and an additional entry in case there are 0 icons on the line.
	// Note:  we can't do this in the constructor because we have to call
	// getReelCount.
	ASSERT( countof( m_aLineWinSpinResults[0] ) == getReelCount( MODE_NORMAL ) + 1 );

	// Now make sure that both game modes have the same number of reels.
	ASSERT( getReelCount( MODE_NORMAL ) == getReelCount( MODE_FREE_SPIN ) );

	// Finally just check to see if the gut is within the right range.
    return ( getGutsId() >= 20000 && getGutsId() < 20100 );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 FieldOfGreenGuts::getGameModeMultiplierAndNoteId( uint8& nGameModeMultiplier, uint8& nNoteId )
///
/// @param   nGameModeMultiplier	The multiplier for the game mode.
/// @param   nNoteId				The note ID for the game mode.
///
/// This helper method is used to get the game mode multiplier and note ID.
////////////////////////////////////////////////////////////////////////////
void FieldOfGreenGuts::getGameModeMultiplierAndNoteId( uint8& nGameModeMultiplier,
	uint8& nNoteId )
{
	// If we are in free spin mode...
    if ( getGameModeId() == MODE_FREE_SPIN )
    {
		// then return the free spin multiplier...
        nGameModeMultiplier = MULTIPLIER_FREE_SPIN;

		// and the free spin note.
        nNoteId = NOTE_FREE_SPIN;
    }
	// Otherwise...
    else
    {
		// just defer to the base class.
        SlotGuts::getGameModeMultiplierAndNoteId( nGameModeMultiplier, nNoteId );
    }
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 FieldOfGreenGuts::hasSavedGames()
///
/// @param   bool8   True/False indicating if this machine supports saved gamees.
///
/// This is a framework override to determine if this machine supports saved games.
////////////////////////////////////////////////////////////////////////////
bool8 FieldOfGreenGuts::hasSavedGames()
{
	// We support saved games so always return true.
	return true;
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 FieldOfGreenGuts::getKickResult()
///
/// This helper method is used to get the subgame data that tracks 
/// what prize the player won for the specified kick.
////////////////////////////////////////////////////////////////////////////
uint8 FieldOfGreenGuts::getKickResult( int32 nKick )
{
	ASSERT( nKick >=0 );
	ASSERT( nKick < 5 );

	// Just return the subgame data.
	return m_subGame->getData( SGDIDX_KICK_1_RESULT + nKick );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 FieldOfGreenGuts::setKickResult()
///
/// This helper method is used to set the subgame data that tracks 
/// what prize the player won for the specified kick.
////////////////////////////////////////////////////////////////////////////
void FieldOfGreenGuts::setKickResult( int32 nKick, uint8 nResult )
{
	ASSERT( nKick >=0 );
	ASSERT( nKick < 5 );

	// Just store the new value in the subgame data.
    m_subGame->update( SGDIDX_KICK_1_RESULT + nKick, nResult );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 FieldOfGreenGuts::getCurrentKick()
///
/// This helper method is used to get the subgame data that tracks 
/// what kick we are on.
////////////////////////////////////////////////////////////////////////////
uint8 FieldOfGreenGuts::getCurrentKick()
{
	// Just return the subgame data.
	return m_subGame->getData( SGDIDX_CURRENT_KICK );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 FieldOfGreenGuts::setCurrentKick()
///
/// This helper method is used to set the subgame data that tracks 
/// what kick we are on.
////////////////////////////////////////////////////////////////////////////
void FieldOfGreenGuts::setCurrentKick( uint8 nKick )
{
	// Just store the new value in the subgame data.
    m_subGame->update( SGDIDX_CURRENT_KICK, nKick );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 FieldOfGreenGuts::incrementCurrentKick()
///
/// This helper method is used to increment the subgame data that tracks 
/// what kick we are on.
////////////////////////////////////////////////////////////////////////////
void FieldOfGreenGuts::incrementCurrentKick()
{
	setCurrentKick( getCurrentKick() + 1 );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 FieldOfGreenGuts::getNumKicks()
///
/// This helper method is used to get the subgame data that tracks 
/// how many kicks we have.
////////////////////////////////////////////////////////////////////////////
uint8 FieldOfGreenGuts::getNumKicks()
{
	// Just return the subgame data.
	return m_subGame->getData( SGDIDX_NUM_KICKS );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 FieldOfGreenGuts::setNumKicks()
///
/// This helper method is used to set the subgame data that tracks 
/// how many kicks we have.
////////////////////////////////////////////////////////////////////////////
void FieldOfGreenGuts::setNumKicks( uint8 nKicks )
{
	// Just store the new value in the subgame data.
    m_subGame->update( SGDIDX_NUM_KICKS, nKicks );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 FieldOfGreenGuts::setRightToLeftLineWin()
///
/// This function sets the right to left line win flag for the passed in
/// line.
////////////////////////////////////////////////////////////////////////////
void FieldOfGreenGuts::setRightToLeftLineWin( uint8 nLine )
{
	// Get the current flags.
	int32 n = m_subGame->getData( SGDIDX_RIGHT_TO_LEFT_LINE_WINS );

	// Turn on the flag for the new line.
	n |= 1 << nLine;

	// Store the new flags in the sub-game data.
    m_subGame->update( SGDIDX_RIGHT_TO_LEFT_LINE_WINS, n );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 FieldOfGreenGuts::resetRightToLeftLineWins()
///
/// This function resets all of the right to left line win flags in
/// preparation for a new spin.
////////////////////////////////////////////////////////////////////////////
void FieldOfGreenGuts::resetRightToLeftLineWins()
{
	// Just set the sub-game data back to zero.
    m_subGame->update( SGDIDX_RIGHT_TO_LEFT_LINE_WINS, 0 );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 FieldOfGreenGuts::resetDataForNextSpin()
///
/// This method is overridden to initialize the sub-game data.
////////////////////////////////////////////////////////////////////////////
void FieldOfGreenGuts::resetDataForNextSpin()
{
	// Let the base class reset it's data first.
	SlotGuts::resetDataForNextSpin();

	// Reset all of the right to left line win flags.
	resetRightToLeftLineWins();

	// Initialize the current kick.
	setCurrentKick( 0 );

	// Initialize the number of kicks.
	setNumKicks( 0 );

	// Initialize the kick results.
	for ( int n = 0; n < 5; n++ )
	{
		setKickResult( n, KR_INVALID );
	}
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 FieldOfGreenGuts::processClientData()
///
/// @param   bonusGameType      The current type of bonus game.
/// @param   bonusDataCount     The number of integers passed from the client.
/// @param   bonusData			An array of integers passed from the client.
/// 
/// This is an override of the framework method.
/// 
////////////////////////////////////////////////////////////////////////////
bool8 FieldOfGreenGuts::processClientData( uint8 bonusGameType, int32 bonusDataCount, int32 *bonusData )
{
	// Make sure the bonus game is active (in case somebody is trying to hack us)
	if ( getBonusGameState() == BONUS_GAME_INACTIVE )
	{
		return false;
	}

	// Make sure the bonus game type is correct (in case somebody is trying to hack us)
	if ( bonusGameType != BONUS_GAME_FIELD_GOAL_FEATURE )
	{
		return false;
	}

	// Make sure the data count is correct (in case somebody is trying to hack us)
	if ( bonusDataCount != 1 )
	{
		return false;
	}

	// Make sure the pointer is not NULL.  I'm not sure how this could happen, but we
	// don't want to crash if it does.
	if ( bonusData == NULL )
	{
		ASSERT( false );
		return false;
	}

	// Make sure we have bonus games.
	if ( getCurrentKick() >= getNumKicks() )
	{
		return false;
	}

	// Initialize a local to hold the players result.
	uint8 nResult = getRandomValueFromProbabilityTable( PROB_TABLE_KICK_RESULTS );

	// Store the result for the client.
	setKickResult( getCurrentKick(), nResult );

	// Add the bonus game for this result.
	addBonus( nResult );

	// Move to the next kick.
	incrementCurrentKick();

	// If we are done...
	if ( getCurrentKick() == getNumKicks() )
	{
		// then finish up
		setGameCanComplete( true );
		setBonusGameState( BONUS_GAME_INACTIVE );

		// If the bonus prize did not put us over the max payout...
		if ( !getMaxPayoutAwarded() )
		{
			// then we might need to go into free spin mode.
			if ( getFreeSpins() )
			{
				// Note:  We might already be in free spin mode, but that is OK.
				setGameModeId( MODE_FREE_SPIN );
			}
		}
	}

	return true;
}
